﻿// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only

#include <iostream>
#include <QObject>
#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QDir>
#include <QErrorMessage>
#include <QJsonObject>
#include <Drillingrig.h>
#include <QTimer>
#include <QThread>
#include <QQuickWindow>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QFile>
#include <QLibrary>
#include <QMessageBox>
#include <QProcess>
#include "app_environment.h"
#include "import_qml_plugins.h"
#include "ConfigHelper.h"
#include "LicenseAdministrator.h"
#include "SystemInterface.h"

class SystemOpenCountImp : public SystemInterface
{
public:
	SystemOpenCountImp(QJsonObject const& root) {		
		__usecount = root["useCount"].toInt(1);
	}
	int startupCount() const  override {
		return __usecount;
	}
	~SystemOpenCountImp() {
		incUseCount();
	}
private:
	void incUseCount() {
		QFile file("./config/license.json");
		QJsonObject obj;
		++__usecount;
		obj["useCount"] = __usecount;
		QJsonDocument doc;
		doc.setObject(obj);
		if (!file.open(QIODevice::WriteOnly)) {
			qDebug() << u8"配置文件写入失败: " << file.errorString();
		}
		file.write(doc.toJson());
		file.close();
	}
private:
	int __usecount = 0;
};


bool loadConfig(Drillingrig* core, QJsonObject const& obj) {
	if (!core) {
		return false;
	}
	if (!obj.contains("server")) {
		return false;
	}
	core->setBridge(obj["server"].toObject());
	if (!obj.contains("modbus")) {
		return false;
	}
	core->setModbus(obj["modbus"].toObject());

	return true;
}

bool checkLicense(QJsonObject const& root) {
	std::shared_ptr<SystemInterface> spm = std::make_shared<SystemOpenCountImp>(root);
	char logFileName[] = { 'p','r','e','-','L','i','c','e','n','s','e','\0' };
	typedef LicenseVerify* (*LibrayLic)();
	LibrayLic create = (LibrayLic)QLibrary::resolve("LicenseClient.dll", "make_verify_interface");
	if (!create) {
		std::throw_with_nested(std::exception("LicenseClient.dll throw excetion!"));
	}
	LicenseVerify* user_ptr = create();
	if (!user_ptr) {
		std::throw_with_nested(std::exception("LicenseClient create object throw excetion!"));
	}
	if (spm->startupCount() == 0) {				//开始验证是是否第一次打开计数
		user_ptr->writFirst();
		return false;
	}
	else {
		qDebug() << "check license";
		if (!user_ptr->checkTimeout(true)) {							//验证是否到期
			QJsonObject obj;
			qDebug() << user_ptr->getCpuSerialNum();
			qDebug() << user_ptr->getUuid();
			obj["uuid"] = QString(user_ptr->getUuid());
			obj["mask"] = QString(user_ptr->getCpuSerialNum());
			QJsonDocument doc;
			doc.setObject(obj);
			QFile logFile(logFileName);
			logFile.open(QIODevice::WriteOnly | QIODevice::Truncate);
			logFile.write(doc.toJson());
			logFile.waitForBytesWritten(1000);
			logFile.close();
			qDebug() << QStringLiteral("程序是没有授权的");
			QMessageBox::critical(nullptr, QStringLiteral("授权"), QStringLiteral("授权到期，请联系开发人员!"));
			std::throw_with_nested(std::exception(doc.toJson()));
			return false;
		}
		return true;
	}
	return false;
}

class Connections : public QObject
{
public:
	Connections(QObject* parent = nullptr) : QObject(parent) {}
	void operator()() {
		qDebug() << QStringView(u"开始执行初始化连接服务");
		for (auto it = funcs.begin(); it != funcs.end(); it++) {
			(*it)();
		}
	}
	std::list<std::function<void()>> funcs;
};

void handleEptr(std::exception_ptr eptr) {
	static std::mutex ms_mutex;
	std::lock_guard<std::mutex> lock(ms_mutex);
	try {
		if (eptr) {
			std::rethrow_exception(eptr);
		}
	}
	catch (std::exception const& e) {
		std::cerr << "Capture exception : " << e.what() << std::endl;
		QErrorMessage d;
		d.showMessage(QString::fromLocal8Bit(e.what()));
		d.exec();
		exit(-1);
	}
}

int main(int argc, char* argv[]) {
	qDebug() << argv[1];
	qputenv("QT_MEDIA_BACKEND", "ffmpeg");
	auto path = qgetenv("PATH");
	path += ";";
	int result = 0;
	set_qt_environment();
	QApplication app(argc, argv);
	QString vlcPath = QDir(QCoreApplication::applicationDirPath() + "/../vlc").absolutePath();
	path += vlcPath.toLocal8Bit();
	qputenv("PATH", path);

	//QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL);
	QDir::setCurrent(QCoreApplication::applicationDirPath());
	QQmlApplicationEngine engine;
	
	std::exception_ptr eptr;
	Connections connections;
	const QUrl url(u"qrc:/qt/qml/Main/main.qml"_qs);
	QObject::connect(&engine,
		&QQmlApplicationEngine::objectCreated,
		&app,
		[url, &connections](QObject* obj, const QUrl& objUrl) {
			if (!obj && url == objUrl) {
				QCoreApplication::exit(-1);
			}
			qDebug() << QStringLiteral("qml加载完成") << qobject_cast<QWindow*>(obj);
			QTimer::singleShot(3000, Qt::VeryCoarseTimer, &connections, &Connections::operator());
	},
	Qt::QueuedConnection);
	engine.addImportPath(QCoreApplication::applicationDirPath() + "/qml");
	engine.addImportPath(":/");
#ifndef _DEBUG
	//    首先检查授权信息
	/*try {
		QFile file("./config/license.json");
		if (!file.open(QIODevice::ReadOnly)) {
			qDebug() << QStringLiteral("配置文件打开失败: ") + file.errorString();
			QMessageBox::critical(nullptr, QStringLiteral("授权"), QStringLiteral("授权文件打开失败!"));
			app.quit();
			return -1;
		}
		QJsonParseError error;
		QJsonDocument doc = QJsonDocument::fromJson(file.readAll(), &error);
		if (error.error != QJsonParseError::NoError) {
			qDebug() << QStringLiteral("配置文件解析失败: ") + error.errorString();
			QMessageBox::critical(nullptr, QStringLiteral("授权"), QStringLiteral("授权文件解析失败!"));
			app.quit();
			return -1;
		}
		if (!checkLicense(doc.object())) {
			app.quit();
			return -1;
		}
	}
	catch (...) {
		eptr = std::current_exception();
	}
	handleEptr(eptr);*/
#endif
	try {
		ConfigHelper* configHelper = new ConfigHelper(QApplication::applicationDirPath() + "/config/AppConfig.json"
			, &engine);
		Drillingrig core(engine.rootContext(),
			&engine);
		engine.rootContext()->setContextProperty("config", configHelper);
		connections.funcs.push_back([&]()->void {
			if (!loadConfig(&core, configHelper->rootObject())) {
				QCoreApplication::exit(-1);
			}
		});
		QObject::connect(&core, &Drillingrig::loadFinished, &engine, [&engine, url] {
			QThread::msleep(1000);
			qDebug() << QStringLiteral("开始加载qml");
			engine.load(url);
			if (engine.rootObjects().isEmpty()) {
				QCoreApplication::quit();
			}
		});
		//engine.load(url);
		
		result = app.exec();
	}
	catch (...) {
		eptr = std::current_exception();
	}
	handleEptr(eptr);
	return result;
}
